package com.educhains.web.util;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import java.awt.Color;

import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.text.Style;

/**
 * @author YuRun
 * @since 2017年8月21日
 */
public class ImageCaptchaUtils {

    private static Logger logger = LogManager.getLogger(ImageCaptchaUtils.class);

    private static String fontByteStr = "";

    private static String[] fontName =
            {
                    "Algerian", "Arial", "Arial Black", "Agency FB", "Calibri", "Cambria", "Gadugi", "Georgia", "Consolas", "Comic Sans MS", "Courier New",
                    "Gill sans", "Time News Roman", "Tahoma", "Quantzite", "Verdana"
            };

    private static int[] fontStyle =
            {
                    Font.BOLD, Font.ITALIC, Font.ROMAN_BASELINE, Font.PLAIN, Font.BOLD + Font.ITALIC
            };

    private static Color[] colorRange =
            {
                    Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW, Color.GREEN, Color.BLUE,
                    Color.DARK_GRAY, Color.BLACK, Color.RED
            };

    private static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz";


    static {
        InputStream in = null;
        try {
            in = ImageCaptchaUtils.class.getResourceAsStream("font");
            fontByteStr = IOUtils.toString(in, "UTF-8");
        } catch (Exception e) {
            logger.error("Failed to get img font. e: " + e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    public static void outputImage(int width, int height, int lineCount, String code, OutputStream sos) throws IOException {
        int x = 0, fontHeight = 0, codeY = 0;
        int red = 0, green = 0, blue = 0;

        x = width / 6;// 每个字符的宽度
        fontHeight = height - 2;// 字体的高度
        codeY = height - 4;

        BufferedImage buffImg = null;
        // 图像buffer
        buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = buffImg.createGraphics();
        // 生成随机数
        Random random = new Random();
        // 将图像填充为白色
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);
        // 创建字体
        Font font = getFont(fontHeight);
        g.setFont(font);

        for (int i = 0; i < lineCount; i++) {
            int xs = random.nextInt(width);
            int ys = random.nextInt(height);
            int xe = xs + random.nextInt(width / 8);
            int ye = ys + random.nextInt(height / 8);
            red = random.nextInt(255);
            green = random.nextInt(255);
            blue = random.nextInt(255);
            g.setColor(new Color(red, green, blue));
            g.drawLine(xs, ys, xe, ye);
        }

        // randomCode记录随机产生的验证码
        StringBuffer randomCode = new StringBuffer();
        // 随机产生codeCount个字符的验证码。
        for (int i = 0; i < code.length(); i++) {
            String strRand = code.substring(i, i + 1);
            // 产生随机的颜色值，让输出的每个字符的颜色值都将不同。
            red = random.nextInt(255);
            green = random.nextInt(255);
            blue = random.nextInt(255);
            g.setColor(new Color(red, green, blue));
            g.drawString(strRand, (i + 1) * x, codeY);
            // 将产生的四个随机数组合在一起。
            randomCode.append(strRand);
        }
        code = randomCode.toString();
        write(sos, buffImg);
    }

    private static void write(OutputStream sos, BufferedImage buffImg) throws IOException {
        ImageIO.write(buffImg, "png", sos);
        sos.close();
    }

    public static String generateVerifyCode(int verifySize) {
        return generateVerifyCode(verifySize, VERIFY_CODES);
    }

    private static String generateVerifyCode(int verifySize, String sources) {
        if (sources == null || sources.length() == 0) {
            sources = VERIFY_CODES;
        }
        int codesLen = sources.length();
        Random rand = new Random(System.currentTimeMillis());
        StringBuilder verifyCode = new StringBuilder(verifySize);
        for (int i = 0; i < verifySize; i++) {
            verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
        }

        return verifyCode.toString();
    }

    private static Font getFont(int fontHeight) {
        try {
            Font baseFont = Font.createFont(Font.TRUETYPE_FONT,
                    new ByteArrayInputStream(hex2byte(fontByteStr)));
            return baseFont.deriveFont(Font.PLAIN, fontHeight);
        } catch (Exception e) {
            Random random = new Random();
            int length = fontName.length;
            String font = fontName[random.nextInt(length)];
            return new Font(font, Font.PLAIN, fontHeight);
        }
    }

    private static byte[] hex2byte(String str) {
        if (str == null)
            return null;
        str = str.trim();
        int len = str.length();
        if (len == 0 || len % 2 == 1)
            return null;

        byte[] b = new byte[len / 2];
        try {
            for (int i = 0; i < str.length(); i += 2) {
                b[i / 2] = (byte) Integer.decode("0x" + str.substring(i, i + 2)).intValue();
            }
            return b;
        } catch (Exception e) {
            return null;
        }
    }

}